home *** CD-ROM | disk | FTP | other *** search
- Path: uunet!tektronix!tekgen!tekred!games
- From: games@tekred.CNA.TEK.COM
- Newsgroups: comp.sources.games
- Subject: v06i051: connect4 - connect four opponent (you vs the computer)
- Message-ID: <3887@tekred.CNA.TEK.COM>
- Date: 26 Apr 89 18:18:27 GMT
- Sender: billr@tekred.CNA.TEK.COM
- Lines: 1517
- Approved: billr@saab.CNA.TEK.COM
-
- Submitted-by: speedboat jones <tcjones@watdragon.waterloo.edu>
- Posting-number: Volume 6, Issue 51
- Archive-name: connect4
-
- [from the author:]
- [[Hi there. Lots of people have asked about Connect Four here in the past
- (or so it seems). Some months ago I wrote this Connect Four opponent
- (i.e. you against the machine) and intended to clean it up alot before
- ever posting it. Anyway now I'm leaving the net world and so I thought
- I'd let it out. Caveat emptor and all that.
-
- This should compile just fine on BSD with curses, others will have to
- make some changes though. See the README and Install files for
- information.
-
- Terry Jones]]
- #! /bin/sh
- # This is a shell archive. Remove anything before this line, then unpack
- # it by saving it into a file and typing "sh file". To overwrite existing
- # files, type "sh file -c". You can also feed this as standard input via
- # unshar, or by typing "sh <file", e.g.. If this archive is complete, you
- # will see the following message at the end:
- # "End of archive 1 (of 1)."
- # Contents: README MANIFEST Install Makefile c4.c c4.h screen.c
- # tables.h types.h
- # Wrapped by billr@saab on Wed Apr 26 11:16:15 1989
- PATH=/bin:/usr/bin:/usr/ucb ; export PATH
- if test -f 'README' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'README'\"
- else
- echo shar: Extracting \"'README'\" \(2266 characters\)
- sed "s/^X//" >'README' <<'END_OF_FILE'
- XREADME.
- X
- X
- XThis is a Connect Four opponent. It was written under BSD4.3 and uses
- Xcurses. Modifications to make it work on other Unices should be
- Xrelatively minor - I can think of perhaps 4 or 5 things that would need
- Xdoing.
- X
- XI am a little hesitant about releasing this now as it is far from what
- XI would call a finished thing and the code is ugly. It came about after
- Xa few hours thinking about how I could write such a thing (data
- Xstructures and strategy and so forth) and then one night of hacking to
- Xget something working. Since then it has been through several revisions
- Xof strategy, but I still consider it to be missing at least one ability
- Xthat humans seem to employ when playing. I intend to add this, but not
- Xin the immediate future.
- X
- XI am also hesitant about putting this into widespread distribution as
- XConnect Four is undoubtedly a trade mark or some such of Milton Bradley
- Xand I don't want to be woken up by phone calls from their lawyers.
- X
- XI just took another look at all the code etc and I'm really not very
- Xhappy with it. Oh well. Flames meekly accepted - as long as you let me
- Xsay "I already knew that..." :-)
- X
- XI'm happy to discuss strategies and improvements you might like to
- Xsuggest. I'd also be happy to see this code developed further, but at
- Xthe same time feel a little possessive about it :-( But, since I am too
- Xbusy to do anything more for the present, you have permission to do
- Xanything with this code and there is no real need to consult me.
- X
- XThere are very few comments in the code. I am planning to spend quite a
- Xfew hours adding some before I lay this to rest and get back to my
- Xschoolwork - just so that when I return to it in a year (or whenever) I
- Xwon't get that sinking feeling of not understanding one's own code
- Xanymore. Or something like that.
- X
- XAbove all - have fun etc etc. See the file 'Install' for instructions on
- Xgetting this up and going.
- X
- XRegards,
- XTerry Jones
- X
- XDepartment Of Computer Science, University Of Waterloo
- XWaterloo Ontario Canada N2L 3G1. Phone: 1-519-8884674
- XUUCP: ...!watmath!watdragon!tcjones
- XCSNET, Internet, CDNnet: tcjones@dragon.waterloo.{cdn,edu}
- XBITNET: tcjones@WATER.bitnet
- XCanadian domain: tcjones@dragon.uwaterloo.ca
- END_OF_FILE
- if test 2266 -ne `wc -c <'README'`; then
- echo shar: \"'README'\" unpacked with wrong size!
- fi
- # end of 'README'
- fi
- if test -f 'MANIFEST' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'MANIFEST'\"
- else
- echo shar: Extracting \"'MANIFEST'\" \(393 characters\)
- sed "s/^X//" >'MANIFEST' <<'END_OF_FILE'
- X File Name Archive # Description
- X-----------------------------------------------------------
- X Install 1
- X MANIFEST 1 This shipping list
- X Makefile 1
- X README 1
- X c4.c 1
- X c4.h 1
- X screen.c 1
- X tables.h 1
- X types.h 1
- END_OF_FILE
- if test 393 -ne `wc -c <'MANIFEST'`; then
- echo shar: \"'MANIFEST'\" unpacked with wrong size!
- fi
- # end of 'MANIFEST'
- fi
- if test -f 'Install' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'Install'\"
- else
- echo shar: Extracting \"'Install'\" \(2209 characters\)
- sed "s/^X//" >'Install' <<'END_OF_FILE'
- XInstall
- X
- XIf you are running BSD then lucky for you! Just type make and it should
- Xcompile ok. If not then you'll have to make some fixes. If you can't
- Xfigure out what they are then I may be willing to help - send
- Xcompiler messages etc and I will try and make it work on a system5 or
- Xultrix or dynix machine here. I am only able to give limited support
- Xbecause I don't have alot of time for this stuff during term.
- X
- XA few things to note are....
- X
- XIf SCOREFILE is not defined in the Makefile or header file,
- Xc4 should be chmod'd to 4511 and will keep a log in the home directory
- Xof the file's owner. The log will show the results of every game that
- Xis played. This is very useful for looking for bugs and finding out
- Xwhat sort of things the game does wrong in an attempt to improve its
- Xstrategy etc. There is a debug option available that writes a file
- Xcalled 'debug' in the current directory. (You need to change 'wizard'
- Xin c4.c if you wish to use debugging - you shouldn't have to). There
- Xis alot of output and so you can toggle debug on and off using a 'd'
- Xwhilst playing. The debug on/off routines check to see that your userid
- Xis 'tcjones' so you will probably want to change that. All debugging
- Xprintfs are done with the DP #define - which will eventually vanish if
- Xthis ever gets released properly.
- X
- XAlso there is a char *[] table called 'experts' in tables.h. If a
- Xuserid in this table is playing, it will not ask whether help is
- Xrequired. This also I will change if ever I rewrite this thing - it
- Xshould check the scorefile to see if this person has played before.
- X
- XThere is a -S option to list the scorefile. I tend to find that people
- Xare less willing to play the game if they know that others can look at
- Xtheir results (hence S not s). I plan to make this better too - so that
- Xyou can ask for the scores for a particular person etc.
- X
- XThere is a -1 option to say "I want to go first" and a -2 option to say
- X"I want to go second".
- X
- XThere are MANY things I want to add and change. This grew out of a
- Xsocket based program that let one person play another, but that has
- Xdisappeared. I'd like to put it back. I'd like to make it possible to
- Xwithdraw moves, to save/restore games and other things.
- X
- XTerry
- END_OF_FILE
- if test 2209 -ne `wc -c <'Install'`; then
- echo shar: \"'Install'\" unpacked with wrong size!
- fi
- # end of 'Install'
- fi
- if test -f 'Makefile' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'Makefile'\"
- else
- echo shar: Extracting \"'Makefile'\" \(235 characters\)
- sed "s/^X//" >'Makefile' <<'END_OF_FILE'
- X# Makefile for c4
- X
- XCFLAGS = -g #-DSCOREFILE=\"/usr/games/lib/c4.scores\"
- XCURSES = -lcurses -ltermcap
- X
- Xc4 : c4.o screen.o c4.h tables.h types.h
- X cc $(CFLAGS) -o c4 c4.o screen.o $(CURSES)
- X
- Xscreen.o : c4.h
- X
- Xc4.o : c4.h tables.h types.h
- END_OF_FILE
- if test 235 -ne `wc -c <'Makefile'`; then
- echo shar: \"'Makefile'\" unpacked with wrong size!
- fi
- # end of 'Makefile'
- fi
- if test -f 'c4.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'c4.c'\"
- else
- echo shar: Extracting \"'c4.c'\" \(18926 characters\)
- sed "s/^X//" >'c4.c' <<'END_OF_FILE'
- X/*
- X * c4.h - Connect Four game using curses.
- X *
- X *
- X * Terry Jones. December 28, 1988.
- X *
- X * Department Of Computer Science, University Of Waterloo
- X * Waterloo Ontario Canada N2L 3G1. Phone: 1-519-8884674
- X * UUCP: ...!watmath!watdragon!tcjones
- X * CSNET, Internet, CDNnet: tcjones@dragon.waterloo.{cdn,edu}
- X * BITNET: tcjones@WATER.bitnet
- X * Canadian domain: tcjones@dragon.uwaterloo.ca
- X *
- X */
- X
- X#include <stdio.h>
- X#include <sys/types.h>
- X#include <ctype.h>
- X#include <pwd.h>
- X#include <sys/time.h>
- X#include <sys/file.h>
- X#include <sys/param.h>
- X#include "c4.h"
- X#include "types.h"
- X#include "tables.h"
- X
- X#define DP if (d) fprintf
- X#define DD if (d)
- X#ifndef MAXHOSTNAMELEN
- X#define MAXHOSTNAMELEN 64 /* from sys/param.h on vanilla 4.3bsd */
- X#endif
- X
- Xwin_list_t win_list;
- Xboard_t board;
- Xint moves_played = 0;
- Xchar *myname;
- Xu_char game_record[SQUARES];
- XFILE *scorefile;
- XFILE *d = NULL;
- XFILE *save = NULL;
- Xchar *u_name = "Bozo";
- Xchar *version = "3.2";
- Xchar *release_date = "8pm, January 1st, 1988";
- Xint turn = GAME_OVER;
- Xint first;
- Xchar *wizard = "tcjones";
- X
- Xmain(argc, argv, envp)
- Xint argc;
- Xchar **argv;
- Xchar **envp;
- X{
- X register int move;
- X register int square;
- X register int winner = DRAW;
- X int temp;
- X
- X envmesg(envp, "Connect Four");
- X do_args(argc, argv);
- X open_scorefile("a");
- X ask_help();
- X first = turn = turn == GAME_OVER ? ask_turn() : turn;
- X init_win_list_t(&win_list);
- X init_board_t(&board);
- X init_screen();
- X accept_move(turn);
- X
- X for (;;){
- X if (moves_played == SQUARES){
- X turn = GAME_OVER;
- X }
- X
- X DP(d, "\n<<< M O V E = %d >>>\n", moves_played + 1);
- X
- X if (turn == GAME_OVER) break;
- X
- X if (turn == THEIRS){
- X move = get_move();
- X }
- X else{
- X move = think_of_fucking_clever_move();
- X }
- X
- X square = update_column(move);
- X
- X if (square < 0){
- X bell();
- X report("That column is full!");
- X if (turn == OURS){
- X winner = CONFUSED;
- X turn = GAME_OVER;
- X report("column %2d, square %2d", move, square);
- X }
- X accept_move(turn);
- X continue;
- X }
- X
- X fill_column(move, turn);
- X show_move(move, turn);
- X
- X update_game_record(move);
- X update_board(&board, square, turn);
- X update_win_list(&win_list, square, turn);
- X if ((temp = count(&win_list, (u_char) 4, turn))){
- X DP(d, "Temp from count is %d\n", temp);
- X winner = turn;
- X turn = GAME_OVER;
- X }
- X else{
- X turn = turn == OURS ? THEIRS : OURS;
- X }
- X }
- X plot_finish();
- X print_game_record(winner);
- X goodbye();
- X}
- X
- Xvoid
- Xinit_win_list_t(w_list)
- Xwin_list_t *w_list;
- X{
- X register int i;
- X
- X for (i = 0; i < WINS; i++){
- X w_list->us[i] = w_list->them[i] = (u_char) 0;
- X }
- X}
- X
- Xvoid
- Xinit_board_t(bd)
- Xboard_t *bd;
- X{
- X register int i;
- X
- X for (i = 0; i < SQUARES; i++){
- X bd->square[i] = EMPTY;
- X }
- X}
- X
- X
- Xvoid
- Xprint_in_what_wins()
- X{
- X register int i;
- X for (i = 0; i < SQUARES; i++){
- X int index = cum_index[i];
- X printf("Sq %2d (offset = %3d) :", i, index);
- X while (in_what_wins[index] != (u_char) -1){
- X printf(" %d", in_what_wins[index++]);
- X }
- X printf("\n");
- X }
- X}
- X
- X
- Xint
- Xget_move()
- X{
- X register int move;
- X
- X get: move = getchar();
- X
- X switch(move){
- X
- X /* COLUMN # */
- X case '0': case '1': case '2': case '3': case '4': case '5': case '6':{
- X return move - '0';
- X }
- X
- X /* QUIT */
- X case 'q' :
- X case 'x' :{
- X print_game_record(QUIT);
- X plot_finish();
- X printf("Chicken...\n");
- X goodbye();
- X }
- X
- X case 'v':{
- X report("Version %s. Released %s", version, release_date);
- X accept_move(turn);
- X goto get;
- X }
- X
- X /* DEBUG */
- X case 'd':{
- X if (d)
- X debug_off();
- X else
- X debug_on();
- X goto get;
- X }
- X
- X /* CONTROL L (redraw screen) */
- X case 0xc:{
- X register int i;
- X plot_screen();
- X reset_row_levels();
- X turn = first;
- X for (i = 0; i < moves_played; i++){
- X fill_column(game_record[i], turn);
- X turn = turn == OURS ? THEIRS : OURS;
- X }
- X accept_move(turn);
- X goto get;
- X }
- X
- X /* RUBBISH */
- X default:{
- X goto get;
- X }
- X }
- X}
- X
- Xint
- Xask_turn()
- X{
- X char line[128];
- X register char *cp;
- X
- X printf("Would you like to go first? (yes/no) -> ");
- X if (!gets(line)){
- X plot_finish();
- X fprintf(stderr, "Could not read input line.\n");
- X goodbye();
- X }
- X
- X cp = line;
- X while (*cp == ' ' || *cp == '\t') cp++;
- X
- X if (*cp == 'n' || *cp == 'N')
- X return OURS;
- X return THEIRS;
- X}
- X
- Xint
- Xupdate_column(col)
- Xint col;
- X{
- X int square = next_in_col[col];
- X next_in_col[col] -= 7;
- X return square;
- X}
- X
- Xvoid
- Xupdate_game_record(move)
- Xint move;
- X{
- X game_record[moves_played] = move;
- X moves_played++;
- X}
- X
- Xvoid
- Xprint_game_record(winner)
- Xint winner;
- X{
- X register int i;
- X char host[MAXHOSTNAMELEN];
- X char *win_str = "won";
- X extern char *date();
- X
- X bell();
- X switch (winner){
- X case OURS:{
- X printf("I won after %d moves.\n", moves_played);
- X break;
- X }
- X case THEIRS:{
- X printf("I lost after %d moves.\n", moves_played);
- X win_str = "lost";
- X break;
- X }
- X case QUIT:{
- X win_str = "quit";
- X break;
- X }
- X case DRAW:{
- X printf("The game is a draw!\n");
- X win_str = "drew";
- X break;
- X }
- X default:
- X case CONFUSED:{
- X win_str = "confused";
- X }
- X }
- X
- X if (gethostname(host, sizeof(host)) == -1){
- X host[0] = '\0';
- X strcat(host, "Unknown");
- X }
- X
- X if (flock(fileno(scorefile), LOCK_EX) == -1){
- X fprintf(stderr, "Could not lock scorefile!\n");
- X return;
- X }
- X
- X if (fseek(scorefile, 0L, 2) == -1){
- X fprintf(stderr, "Could not unlock scorefile!\n");
- X if (flock(fileno(scorefile), LOCK_UN) == -1){
- X fprintf(stderr, "Could not unlock scorefile!\n");
- X }
- X return;
- X }
- X
- X fprintf(scorefile, "Opponent : %s@%s\n", u_name, host);
- X fprintf(scorefile, "Date : %s [version %s]\n", date(), version);
- X fprintf(scorefile, "Result : %s\n", win_str);
- X fprintf(scorefile, "First Move : %s\n", first == OURS ? "Me" : "Them");
- X fprintf(scorefile, "Moves : %d\n", moves_played);
- X fprintf(scorefile, "Record : ");
- X
- X for (i = 0; i < moves_played && i < 21; i++){
- X fprintf(scorefile, "%d ", game_record[i]);
- X }
- X if (moves_played > 21)
- X fprintf(scorefile, "\n ");
- X for (i = 21; i < moves_played; i++){
- X fprintf(scorefile, "%d ", game_record[i]);
- X }
- X fprintf(scorefile, "\n\n");
- X
- X if (flock(fileno(scorefile), LOCK_UN) == -1){
- X fprintf(stderr, "Could not unlock scorefile!\n");
- X return;
- X }
- X}
- X
- Xvoid
- Xupdate_board(bd, sq, whose)
- Xboard_t *bd;
- Xint sq;
- Xint whose;
- X{
- X bd->square[sq] = whose;
- X}
- X
- Xint
- Xupdate_win_list(w_list, sq, whose)
- Xwin_list_t *w_list;
- Xint sq;
- Xint whose;
- X{
- X /*
- X * Update the win list specified by 'whose' and return a measure of
- X * the value of this move.
- X */
- X register int index = (int) cum_index[sq];
- X register u_char *my_list;
- X register u_char *their_list;
- X register int goodness = 0;
- X register int win;
- X int a_good[5];
- X int d_good[5];
- X int i;
- X
- X for (i = 0; i < 5; i++){
- X a_good[i] = attack_good[i];
- X d_good[i] = defend_good[i];
- X }
- X
- X if (whose == OURS){
- X my_list = w_list->us;
- X their_list = w_list->them;
- X }
- X else{
- X my_list = w_list->them;
- X their_list = w_list->us;
- X }
- X
- X DP(d, "\t\tUpdate for square %d, turn = %d\n", sq, turn);
- X while((win = (int)in_what_wins[index]) != (u_char) -1){
- X
- X if (their_list[win] == 0){
- X /* We just put something into a win in which they have none. */
- X goodness += a_good[my_list[win] + 1];
- X DP(d, "\t\tmake a %d in win %d", my_list[win] + 1, win);
- X DP(d, "\t\tgood+=%d goodness=%d\n", a_good[my_list[win] + 1],
- X goodness);
- X if (my_list[win])
- X a_good[my_list[win] + 1] = 0;
- X }
- X else if (my_list[win] == 0){
- X /* We just closed off a win for them. */
- X goodness += d_good[their_list[win] + 1];
- X DP(d, "\t\tstop a %d in win %d", their_list[win] + 1, win);
- X DP(d, "\t\tgood+=%d goodness=%d\n", d_good[their_list[win]+1],
- X goodness);
- X if (their_list[win])
- X d_good[their_list[win] + 1] = 0;
- X }
- X else{
- X DP(d, "\t\tNothing for win %d\n", win);
- X }
- X
- X my_list[win]++;
- X index++;
- X }
- X return goodness;
- X}
- X
- Xvoid
- Xprint_board(bd, f)
- Xboard_t *bd;
- XFILE *f;
- X{
- X register int row = 0;
- X register int col = 0;
- X
- X fprintf(f, "\t 0123456\n");
- X
- X for (row = 0; row < ROWS; row++){
- X fprintf(f, "\t%d", row);
- X
- X for (col = 0; col < COLUMNS; col++){
- X
- X switch(bd->square[row * COLUMNS + col]){
- X case OURS:{
- X fprintf(f, OUR_SYM);
- X break;
- X }
- X case THEIRS:{
- X fprintf(f, THEIR_SYM);
- X break;
- X }
- X case EMPTY:{
- X fprintf(f, BLANK_SYM);
- X break;
- X }
- X default:{
- X fprintf(f, "fucking ugh! board screwup\n");
- X break;
- X }
- X }
- X }
- X
- X fprintf(f, "%d\n", row);
- X }
- X fprintf(f, "\t 0123456\n");
- X}
- X
- Xvoid
- Xgoodbye()
- X{
- X exit(1);
- X}
- X
- Xint
- Xthink_of_fucking_clever_move()
- X{
- X register int i;
- X register int j;
- X register int k;
- X win_list_t tmp_win_i;
- X win_list_t tmp_win_j;
- X win_list_t tmp_win_k;
- X int tmp_cols_i[COLUMNS];
- X int tmp_cols_j[COLUMNS];
- X int col_values_i[COLUMNS];
- X int col_values_j[COLUMNS];
- X int col_values_k[COLUMNS];
- X int max_i;
- X int best_col;
- X board_t tmp_board_i;
- X board_t tmp_board_j;
- X board_t tmp_board_k;
- X
- X for (i = 0; i < COLUMNS; i++){
- X col_values_i[i] = 0;
- X }
- X
- X DP(d, "CLEVER MOVE... board looks like\n");
- X DD print_board(&board, d);
- X DP(d, "---------------------------------\n");
- X
- X for (i = 0; i < COLUMNS; i++){
- X
- X register int max_j;
- X
- X DP(d, "my column %d\n", i);
- X
- X if (next_in_col[i] < 0){
- X DP(d, "my column %d is full\n", i);
- X continue;
- X }
- X
- X tmp_win_i = win_list;
- X tmp_board_i = board;
- X
- X update_board(&tmp_board_i, next_in_col[i], OURS);
- X DP(d, "Updated board...\n");
- X DD print_board(&tmp_board_i, d);
- X col_values_i[i] = update_win_list(&tmp_win_i, next_in_col[i], OURS);
- X
- X if (col_values_i[i] >= attack_good[4])
- X return i;
- X
- X DP(d, "my column %d gets value %d after update\n", i, col_values_i[i]);
- X
- X for (j = 0; j < COLUMNS; j++){
- X tmp_cols_i[j] = next_in_col[j];
- X col_values_j[j] = 0;
- X }
- X tmp_cols_i[i] -= 7;
- X
- X DP(d, "Temporary columns for inner loop... ");
- X for (j = 0; j < COLUMNS; j++){
- X DP(d, "%2d ", tmp_cols_i[j]);
- X }
- X DP(d, "\n");
- X
- X for (j = 0; j < COLUMNS; j++){
- X
- X register int max_k;
- X
- X DP(d, "\this column %d\n", j);
- X if (tmp_cols_i[j] < 0){
- X DP(d, "\this column %d is full\n", j);
- X continue;
- X }
- X
- X tmp_win_j = tmp_win_i;
- X tmp_board_j = tmp_board_i;
- X
- X update_board(&tmp_board_j, tmp_cols_i[j], THEIRS);
- X DP(d, "\tUpdated board...\n");
- X DD print_board(&tmp_board_j, d);
- X col_values_j[j] = update_win_list(&tmp_win_j, tmp_cols_i[j], THEIRS);
- X
- X if (col_values_j[j] >= attack_good[4]){
- X /* He gets a win if we do column i. fudge the value up. */
- X col_values_j[j] += (attack_good[4] << 1);
- X }
- X
- X DP(d, "\this column %d gets value %d after update\n", j, col_values_j[j]);
- X for (k = 0; k < COLUMNS; k++){
- X tmp_cols_j[k] = tmp_cols_i[k];
- X col_values_k[k] = 0;
- X }
- X tmp_cols_j[j] -= 7;
- X for (k = 0; k < COLUMNS; k++){
- X
- X if (tmp_cols_j[k] < 0){
- X continue;
- X }
- X
- X tmp_win_k = tmp_win_j;
- X tmp_board_k = tmp_board_j;
- X update_board(&tmp_board_k, tmp_cols_j[k], OURS);
- X col_values_k[k] = update_win_list(&tmp_win_k, tmp_cols_j[k], OURS);
- X }
- X max_k = 0;
- X for (k = 0; k < COLUMNS; k++){
- X if (col_values_k[k] > max_k){
- X max_k = col_values_k[k];
- X }
- X }
- X
- X col_values_j[j] -= max_k;
- X }
- X
- X max_j = 0;
- X for (j = 0; j < COLUMNS; j++){
- X if (col_values_j[j] > max_j){
- X max_j = col_values_j[j];
- X }
- X }
- X DP(d, "the maximum reply for him has value %d\n", max_j);
- X
- X col_values_i[i] -= max_j;
- X DP(d, "column %d reduced by %d to %d\n", i, max_j, col_values_i[i]);
- X }
- X
- X DP(d, "All of my options have been calculated... ");
- X for (j = 0; j < COLUMNS; j++){
- X DP(d, "%2d ", col_values_i[j]);
- X }
- X DP(d, "\n");
- X
- X best_col = -1;
- X max_i = -4 * attack_good[4];
- X for (i = 0; i < COLUMNS; i++){
- X if (next_in_col[i] >= 0 && col_values_i[i] > max_i){
- X max_i = col_values_i[i];
- X best_col = i;
- X }
- X }
- X DP(d, "The best column is %d\n", best_col);
- X DP(d, "Returning.\n\n\n", best_col);
- X
- X if (best_col == -1){
- X print_game_record(CONFUSED);
- X plot_finish();
- X printf("Heavens above, I'm confused... Sorry.\n");
- X goodbye();
- X
- X }
- X
- X return best_col;
- X}
- X
- X
- Xvoid
- Xask_help()
- X{
- X char line[128];
- X char *cp;
- X struct passwd *pwd;
- X register int i;
- X
- X
- X if (!(pwd = getpwuid(getuid())))
- X return;
- X
- X u_name = pwd->pw_name;
- X
- X for (i = 0; experts[i][0]; i++){
- X if (!strcmp(u_name, experts[i])){
- X return;
- X }
- X }
- X
- X printf("Do you need help (n/y)? -> ");
- X if (!gets(line)){
- X fprintf(stderr, "Could not read input line\n");
- X goodbye();
- X }
- X
- X cp = line;
- X
- X while (*cp == ' ' || *cp == '\t') cp++;
- X
- X if (*cp != 'y' && *cp != 'Y') return;
- X print_help();
- X}
- X
- Xvoid
- Xprint_help()
- X{
- X fprintf(stderr, "The columns are numbered 0 to 6 from left to right.\n");
- X fprintf(stderr, "To enter a move just type the column number.\n");
- X fprintf(stderr, "My tiles will be the X'd ones.\n");
- X fprintf(stderr, "'q' or 'x' on your move will quit the game early.\n");
- X fprintf(stderr, "^L will redraw the screen.\n");
- X fprintf(stderr, "Invoke with -h for this help, -1 to go 1st, -2 to go 2nd.\n");
- X}
- X
- X
- Xvoid
- Xopen_scorefile(mode)
- Xchar *mode;
- X{
- X struct passwd *pwd;
- X char file[256];
- X
- X#ifndef SCOREFILE
- X pwd = getpwuid(geteuid());
- X sprintf(file, "%s/.connect4rc", pwd->pw_dir);
- X#else
- X strcpy(file, SCOREFILE);
- X#endif
- X
- X scorefile = fopen(file, mode);
- X if (!scorefile){
- X fprintf(stderr, "Can't open score file (%s)\n", file);
- X exit(1);
- X }
- X
- X if (setuid(getuid())){
- X fprintf(stderr, "Can't set permissions correctly! Exiting!\n");
- X exit(0);
- X }
- X
- X if (setgid(getgid())){
- X fprintf(stderr, "Can't set group id correctly! Exiting!\n");
- X exit(0);
- X }
- X}
- X
- Xchar *
- Xdate()
- X{
- X /* return pointer to NULL terminated date string */
- X
- X extern char *index();
- X static char time[26];
- X struct timeval v;
- X struct timezone z;
- X char *nl;
- X
- X gettimeofday(&v, &z);
- X sprintf(time,"%s", ctime(&v.tv_sec));
- X
- X if ((nl = index(time, '\n')) == NULL){
- X fprintf(stderr,"date: ctime returned non-newline terminated string.\n");
- X exit(1);
- X }
- X
- X *nl = '\0';
- X return time;
- X}
- X
- Xvoid
- Xdo_args(argc, argv)
- Xint argc;
- Xchar **argv;
- X{
- X myname = argv[0];
- X argv++;
- X
- X while (--argc){
- X if (**argv == '-'){
- X switch (argv[0][1]){
- X case 'S':{
- X do_scores();
- X goodbye();
- X }
- X case 'h':{
- X print_help();
- X goodbye();
- X }
- X case 'v':{
- X printf("Version %s\n", version);
- X printf("Released : %s\n", release_date);
- X goodbye();
- X }
- X case '1':{
- X turn = THEIRS;
- X break;
- X }
- X case '2':{
- X turn = OURS;
- X break;
- X }
- X }
- X }
- X argv++;
- X }
- X}
- X
- X
- Xvoid
- Xdo_scores()
- X{
- X register int c;
- X
- X open_scorefile("r");
- X while ((c = getc(scorefile)) != EOF)
- X putchar(c);
- X}
- X
- X
- Xint
- Xcount(w, n, who)
- Xwin_list_t *w;
- Xu_char n;
- Xint who;
- X{
- X register u_char *list = who == OURS ? w->us : w->them;
- X register int i;
- X register int total = 0;
- X
- X for (i = 0; i < WINS; i++){
- X if (list[i] == n){
- X total++;
- X }
- X }
- X
- X return total;
- X}
- X
- Xvoid
- Xbell()
- X{
- X putchar(7);
- X}
- X
- Xvoid
- Xdebug_on()
- X{
- X if (d) return;
- X if (save){
- X d = save;
- X fprintf(d, "\n\nDEBUG RESUMED after move %d\n\n", moves_played);
- X report("debug resumed");
- X }
- X else{
- X struct passwd *pwd = getpwnam(wizard);
- X if (!pwd || getuid() != pwd->pw_uid){
- X return;
- X }
- X else{
- X d = fopen("debug", "w");
- X if (!d){
- X report("debug could be started (fopen fails)");
- X }
- X else{
- X fprintf(d, "\n\nDEBUG ON after move %d\n\n", moves_played);
- X report("debug on");
- X }
- X }
- X }
- X accept_move(turn);
- X}
- X
- Xvoid
- Xdebug_off()
- X{
- X if (!d) return;
- X fprintf(d, "\n\nDEBUG OFF after move %d\n\n", moves_played);
- X report("debug off");
- X fflush(d);
- X save = d;
- X d = NULL;
- X accept_move(turn);
- X}
- X
- X/*
- X * Modify the environment to put message in the right place for
- X * the w and ps commands to find. Code stolen from MFCF lock
- X * program, originally by Ian!
- X *
- X */
- X
- Xvoid
- Xenvmesg(environ, message)
- Xchar **environ;
- Xchar *message;
- X{
- X /*
- X * Note that this clobbers the environment, so we have to
- X * do it last, after all the getenv and termcap calls.
- X */
- X
- X char *last, *address;
- X while( environ[1] != 0 ) ++environ;
- X last = environ[0] + strlen(environ[0]);/* address of '\0' */
- X last = (char *)((int)last&(~03));/* word boundary */
- X *(int *)last = 0; /* clean out last word */
- X address = last +3 -strlen(message);
- X address = (char *)((int)address&(~03));/* word boundary */
- X *(int *)(address-4) = 0; /* clean out word below */
- X *(int *)(address-8) = 0; /* clean out word below */
- X strcpy( address, message );
- X}
- X
- END_OF_FILE
- if test 18926 -ne `wc -c <'c4.c'`; then
- echo shar: \"'c4.c'\" unpacked with wrong size!
- fi
- # end of 'c4.c'
- fi
- if test -f 'c4.h' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'c4.h'\"
- else
- echo shar: Extracting \"'c4.h'\" \(1221 characters\)
- sed "s/^X//" >'c4.h' <<'END_OF_FILE'
- X/*
- X * c4.h
- X *
- X */
- X
- X#define WINS 69
- X#define SQUARES 42
- X#define ROWS 6
- X#define COLUMNS 7
- X
- X#define GAME_OVER -1
- X#define OURS 0
- X#define THEIRS 1
- X#define EMPTY 2
- X#define DRAW 3
- X#define QUIT 4
- X#define CONFUSED 5
- X
- X#define OUR_SYM "+"
- X#define THEIR_SYM "*"
- X#define BLANK_SYM " "
- X
- Xextern char *date();
- Xextern int ask_turn();
- Xextern int count();
- Xextern int get_move();
- Xextern int make();
- Xextern int opportune();
- Xextern int stop();
- Xextern int think_of_fucking_clever_move();
- Xextern int update_column();
- Xextern int update_win_list();
- Xextern void accept_move();
- Xextern void ask_help();
- Xextern void bell();
- Xextern void debug_off();
- Xextern void debug_on();
- Xextern void do_args();
- Xextern void do_scores();
- Xextern void envmesg();
- Xextern void fill_column();
- Xextern void fill_square();
- Xextern void goodbye();
- Xextern void init_board_t();
- Xextern void init_screen();
- Xextern void init_win_list_t();
- Xextern void open_scorefile();
- Xextern void plot_finish();
- Xextern void plot_screen();
- Xextern void print_board();
- Xextern void print_game_record();
- Xextern void print_help();
- Xextern void print_in_what_wins();
- Xextern void report();
- Xextern void reset_row_levels();
- Xextern void show_move();
- Xextern void update_board();
- Xextern void update_game_record();
- END_OF_FILE
- if test 1221 -ne `wc -c <'c4.h'`; then
- echo shar: \"'c4.h'\" unpacked with wrong size!
- fi
- # end of 'c4.h'
- fi
- if test -f 'screen.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'screen.c'\"
- else
- echo shar: Extracting \"'screen.c'\" \(3076 characters\)
- sed "s/^X//" >'screen.c' <<'END_OF_FILE'
- X#include <stdio.h>
- X#include <curses.h>
- X#include "c4.h"
- X
- X#define BASEY 0
- X#define BASEX 0
- X#define LINE0 " 0 1 2 3 4 5 6 "
- X#define LINE1 ".-------------------------------------------------------."
- X#define LINE2 "| | | | | | | |"
- X#define LINE3 "|-------+-------+-------+-------+-------+-------+-------|"
- X#define LINE4 "`-------------------------------------------------------'"
- X
- Xchar *filler[] = {"XXXXXXX", "OOOOOOO" };
- X
- Xstatic int row_levels[] = {5, 5, 5, 5, 5, 5, 5};
- X
- Xvoid
- Xinit_screen()
- X{
- X initscr();
- X crmode();
- X noecho();
- X plot_screen();
- X}
- X
- Xvoid
- Xplot_screen()
- X{
- X register int i;
- X register int j;
- X
- X clear();
- X move(0,60);
- X standout();
- X printw("C O N N E C T 4");
- X standend();
- X move(4,60);
- X printw(" YOUR MOVE: ");
- X move(7,60);
- X printw(" MY MOVE: ");
- X move(BASEY,BASEX);
- X printw(LINE0);
- X move(BASEY+1,BASEX);
- X printw(LINE1);
- X for (i = 0; i < 6; i++){
- X for (j = 0; j < 2; j++){
- X move(BASEY + 2 + 3*i + j , BASEX);
- X printw(LINE2);
- X }
- X move(BASEY + 4 + 3*i , BASEX);
- X printw(LINE3);
- X }
- X move(BASEY + 19, BASEX);
- X printw(LINE4);
- X refresh();
- X}
- X
- Xvoid
- Xshow_move(column, who)
- Xint column;
- Xint who;
- X{
- X int row;
- X int other_row;
- X
- X if (who == OURS){
- X row = 7;
- X other_row = 4;
- X }
- X else{
- X row = 4;
- X other_row = 7;
- X }
- X
- X move(row, 73);
- X printw("%1d",column);
- X move(other_row, 73);
- X printw(" ");
- X move(other_row, 73);
- X refresh();
- X}
- X
- Xvoid
- Xaccept_move(who)
- Xint who;
- X{
- X int row;
- X
- X if (who == OURS)
- X row = 7;
- X else
- X row = 4;
- X
- X move(row, 73);
- X printw(" ");
- X move(row, 73);
- X refresh();
- X}
- X
- X
- X/* VARARGS1 */
- Xvoid
- Xreport(fmt, a, b, c, d, e, f)
- Xchar *fmt;
- Xchar *a, *b, *c, *d, *e, *f;
- X{
- X move(22, 0);
- X printw(fmt, a, b, c, d, e, f);
- X refresh();
- X}
- X
- Xvoid
- Xplot_finish()
- X{
- X move(23,0);
- X refresh();
- X nocrmode();
- X echo();
- X}
- X
- X
- Xvoid
- Xfill_column(column, colour)
- Xint column;
- Xint colour;
- X{
- X register int i;
- X register int row;
- X
- X row = row_levels[column];
- X row_levels[column]--;
- X
- X for (i = 2; i < 4; i++){
- X move(BASEY + i + 3*row, BASEX + 1 + 8*column);
- X if (colour == OURS) {
- X standout();
- X printw(filler[colour]);
- X standend();
- X }
- X else{
- X printw(filler[colour]);
- X }
- X }
- X refresh();
- X}
- X
- Xvoid
- Xfill_square(square, colour)
- Xint square;
- Xint colour;
- X{
- X register int i;
- X register int row;
- X register int column;
- X
- X row = square / 7;
- X column = square % 7;
- X
- X for (i = 2; i < 4; i++){
- X move(BASEY + i + 3*row, BASEX + 1 + 8*column);
- X if (colour == OURS) {
- X standout();
- X printw(filler[colour]);
- X standend();
- X }
- X else{
- X printw(filler[colour]);
- X }
- X }
- X refresh();
- X}
- X
- X
- Xvoid
- Xreset_row_levels()
- X{
- X register int i;
- X
- X for (i = 0; i < COLUMNS; i++){
- X row_levels[i] = 5;
- X }
- X}
- END_OF_FILE
- if test 3076 -ne `wc -c <'screen.c'`; then
- echo shar: \"'screen.c'\" unpacked with wrong size!
- fi
- # end of 'screen.c'
- fi
- if test -f 'tables.h' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'tables.h'\"
- else
- echo shar: Extracting \"'tables.h'\" \(7047 characters\)
- sed "s/^X//" >'tables.h' <<'END_OF_FILE'
- Xu_char dist_counts[SQUARES] = {
- X 3, 4, 5, 7, 5, 4, 3, /* Row 0 */
- X 4, 6, 8, 10, 8, 6, 4, /* Row 1 */
- X 5, 8, 11, 13, 11, 8, 5, /* Row 2 */
- X 5, 8, 11, 13, 11, 8, 5, /* Row 3 */
- X 4, 6, 8, 10, 8, 6, 4, /* Row 4 */
- X 3, 4, 5, 7, 5, 4, 3 /* Row 5 */
- X};
- X
- Xu_char win_in_what[WINS][4] = {
- X { 0, 1, 2, 3 }, /* Win 0 */
- X { 1, 2, 3, 4 }, /* Win 1 */
- X { 2, 3, 4, 5 }, /* Win 2 */
- X { 3, 4, 5, 6 }, /* Win 3 */
- X { 7, 8, 9, 10 }, /* Win 4 */
- X { 8, 9, 10, 11 }, /* Win 5 */
- X { 9, 10, 11, 12 }, /* Win 6 */
- X { 10, 11, 12, 13 }, /* Win 7 */
- X { 14, 15, 16, 17 }, /* Win 8 */
- X { 15, 16, 17, 18 }, /* Win 9 */
- X { 16, 17, 18, 19 }, /* Win 10 */
- X { 17, 18, 19, 20 }, /* Win 11 */
- X { 21, 22, 23, 24 }, /* Win 12 */
- X { 22, 23, 24, 25 }, /* Win 13 */
- X { 23, 24, 25, 26 }, /* Win 14 */
- X { 24, 25, 26, 27 }, /* Win 15 */
- X { 28, 29, 30, 31 }, /* Win 16 */
- X { 29, 30, 31, 32 }, /* Win 17 */
- X { 30, 31, 32, 33 }, /* Win 18 */
- X { 31, 32, 33, 34 }, /* Win 19 */
- X { 35, 36, 37, 38 }, /* Win 20 */
- X { 36, 37, 38, 39 }, /* Win 21 */
- X { 37, 38, 39, 40 }, /* Win 22 */
- X { 38, 39, 40, 41 }, /* Win 23 */
- X { 0, 7, 14, 21 }, /* Win 24 */
- X { 1, 8, 15, 22 }, /* Win 25 */
- X { 2, 9, 16, 23 }, /* Win 26 */
- X { 3, 10, 17, 24 }, /* Win 27 */
- X { 4, 11, 18, 25 }, /* Win 28 */
- X { 5, 12, 19, 26 }, /* Win 29 */
- X { 6, 13, 20, 27 }, /* Win 30 */
- X { 7, 14, 21, 28 }, /* Win 31 */
- X { 8, 15, 22, 29 }, /* Win 32 */
- X { 9, 16, 23, 30 }, /* Win 33 */
- X { 10, 17, 24, 31 }, /* Win 34 */
- X { 11, 18, 25, 32 }, /* Win 35 */
- X { 12, 19, 26, 33 }, /* Win 36 */
- X { 13, 20, 27, 34 }, /* Win 37 */
- X { 14, 21, 28, 35 }, /* Win 38 */
- X { 15, 22, 29, 36 }, /* Win 39 */
- X { 16, 23, 30, 37 }, /* Win 40 */
- X { 17, 24, 31, 38 }, /* Win 41 */
- X { 18, 25, 32, 39 }, /* Win 42 */
- X { 19, 26, 33, 40 }, /* Win 43 */
- X { 20, 27, 34, 41 }, /* Win 44 */
- X { 0, 8, 16, 24 }, /* Win 45 */
- X { 1, 9, 17, 25 }, /* Win 46 */
- X { 2, 10, 18, 26 }, /* Win 47 */
- X { 3, 11, 19, 27 }, /* Win 48 */
- X { 3, 9, 15, 21 }, /* Win 49 */
- X { 4, 10, 16, 22 }, /* Win 50 */
- X { 5, 11, 17, 23 }, /* Win 51 */
- X { 6, 12, 18, 24 }, /* Win 52 */
- X { 7, 15, 23, 31 }, /* Win 53 */
- X { 8, 16, 24, 32 }, /* Win 54 */
- X { 9, 17, 25, 33 }, /* Win 55 */
- X { 10, 18, 26, 34 }, /* Win 56 */
- X { 10, 16, 22, 28 }, /* Win 57 */
- X { 11, 17, 23, 29 }, /* Win 58 */
- X { 12, 18, 24, 30 }, /* Win 59 */
- X { 13, 19, 25, 31 }, /* Win 60 */
- X { 14, 22, 30, 38 }, /* Win 61 */
- X { 15, 23, 31, 39 }, /* Win 62 */
- X { 16, 24, 32, 40 }, /* Win 63 */
- X { 17, 25, 33, 41 }, /* Win 64 */
- X { 17, 23, 29, 35 }, /* Win 65 */
- X { 18, 24, 30, 36 }, /* Win 66 */
- X { 19, 25, 31, 37 }, /* Win 67 */
- X { 20, 26, 32, 38 } /* Win 68 */
- X};
- X
- X
- Xu_char in_what_wins[] = {
- X
- X 0, 24, 45, -1, /* Square 0 */
- X 0, 1, 25, 46, -1, /* Square 1 */
- X 0, 1, 2, 26, 47, -1, /* Square 2 */
- X 0, 1, 2, 3, 27, 48, 49, -1, /* Square 3 */
- X 1, 2, 3, 28, 50, -1, /* Square 4 */
- X 2, 3, 29, 51, -1, /* Square 5 */
- X 3, 30, 52, -1, /* Square 6 */
- X
- X 4, 24, 31, 53, -1, /* Square 7 */
- X 4, 5, 25, 32, 45, 54, -1, /* Square 8 */
- X 4, 5, 6, 26, 33, 46, 49, 55, -1, /* Square 9 */
- X 4, 5, 6, 7, 27, 34, 47, 50, 56, 57, -1, /* Square 10 */
- X 5, 6, 7, 28, 35, 48, 51, 58, -1, /* Square 11 */
- X 6, 7, 29, 36, 52, 59, -1, /* Square 12 */
- X 7, 30, 37, 60, -1, /* Square 13 */
- X
- X 8, 24, 31, 38, 61, -1, /* Square 14 */
- X 8, 9, 25, 32, 39, 49, 53, 62, -1, /* Square 15 */
- X 8, 9, 10, 26, 33, 40, 45, 50, 54, 57, 63, -1, /* Square 16 */
- X 8, 9, 10, 11, 27, 34, 41, 46, 51, 55, 58, 64, 65, -1, /* Square 17 */
- X 9, 10, 11, 28, 35, 42, 47, 52, 56, 59, 66, -1, /* Square 18 */
- X 10, 11, 29, 36, 43, 48, 60, 67, -1, /* Square 19 */
- X 11, 30, 37, 44, 68, -1, /* Square 20 */
- X
- X 12, 24, 31, 38, 49, -1, /* Square 21 */
- X 12, 13, 25, 32, 39, 50, 57, 61, -1, /* Square 22 */
- X 12, 13, 14, 26, 33, 40, 51, 53, 58, 62, 65, -1, /* Square 23 */
- X 12, 13, 14, 15, 27, 34, 41, 45, 52, 54, 59, 63, 66, -1, /* Square 24 */
- X 13, 14, 15, 28, 35, 42, 46, 55, 60, 64, 67, -1, /* Square 25 */
- X 14, 15, 29, 36, 43, 47, 56, 68, -1, /* Square 26 */
- X 15, 30, 37, 44, 48, -1, /* Square 27 */
- X
- X 16, 31, 38, 57, -1, /* Square 28 */
- X 16, 17, 32, 39, 58, 65, -1, /* Square 29 */
- X 16, 17, 18, 33, 40, 59, 61, 66, -1, /* Square 30 */
- X 16, 17, 18, 19, 34, 41, 53, 60, 62, 67, -1, /* Square 31 */
- X 17, 18, 19, 35, 42, 54, 63, 68, -1, /* Square 32 */
- X 18, 19, 36, 43, 55, 64, -1, /* Square 33 */
- X 19, 37, 44, 56, -1, /* Square 34 */
- X
- X 20, 38, 65, -1, /* Square 35 */
- X 20, 21, 39, 66, -1, /* Square 36 */
- X 20, 21, 22, 40, 67, -1, /* Square 37 */
- X 20, 21, 22, 23, 41, 61, 68, -1, /* Square 38 */
- X 21, 22, 23, 42, 62, -1, /* Square 39 */
- X 22, 23, 43, 63, -1, /* Square 40 */
- X 23, 44, 64, -1 /* Square 41 */
- X};
- X
- Xu_short cum_index[SQUARES] = {
- X 0, 4, 9, 15, 23, 29, 34, /* Squares 0 to 6 */
- X 38, 43, 50, 59, 70, 79, 86, /* Squares 7 to 13 */
- X 91, 97, 106, 118, 132, 144, 153, /* Squares 14 to 20 */
- X 159, 165, 174, 186, 200, 212, 221, /* Squares 21 to 27 */
- X 227, 232, 239, 248, 259, 268, 275, /* Squares 28 to 34 */
- X 280, 284, 289, 295, 303, 309, 314 /* Squares 35 to 41 */
- X};
- X
- Xint next_in_col[COLUMNS] = {
- X 35, 36, 37, 38, 39, 40, 41
- X};
- X
- Xint attack_good[] = {
- X 0, 1, 25, 500, 100000
- X};
- X
- Xint defend_good[] = {
- X 0, 1, 20, 400, 10000
- X};
- X
- Xchar *experts[] = {
- X "tcjones",
- X "ljpoconnor",
- X "pjyamamoto",
- X "gjerawlins",
- X "jshen",
- X "rvklassen",
- X "vlestivill",
- X "rastroobossc",
- X ""
- X};
- END_OF_FILE
- if test 7047 -ne `wc -c <'tables.h'`; then
- echo shar: \"'tables.h'\" unpacked with wrong size!
- fi
- # end of 'tables.h'
- fi
- if test -f 'types.h' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'types.h'\"
- else
- echo shar: Extracting \"'types.h'\" \(132 characters\)
- sed "s/^X//" >'types.h' <<'END_OF_FILE'
- Xtypedef struct {
- X u_char us[WINS];
- X u_char them[WINS];
- X} win_list_t;
- X
- Xtypedef struct {
- X u_char square[SQUARES];
- X} board_t;
- END_OF_FILE
- if test 132 -ne `wc -c <'types.h'`; then
- echo shar: \"'types.h'\" unpacked with wrong size!
- fi
- # end of 'types.h'
- fi
- echo shar: End of archive 1 \(of 1\).
- cp /dev/null ark1isdone
- MISSING=""
- for I in 1 ; do
- if test ! -f ark${I}isdone ; then
- MISSING="${MISSING} ${I}"
- fi
- done
- if test "${MISSING}" = "" ; then
- echo You have the archive.
- rm -f ark[1-9]isdone
- else
- echo You still need to unpack the following archives:
- echo " " ${MISSING}
- fi
- ## End of shell archive.
- exit 0
-